/**
 * @file app_acp.c
 * @brief 
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2021-03-01
 * @copyright Copyright (c) 2021  烽火通信
 ***************************************************************
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version  <th>Author  <th>Description
 * <tr><td>2021-03-01 <td>1.0      <td>wangh   <td>内容
 * <tr><td>2021-09-18 <td>1.0      <td>wangh   <td>1.拨码开关地址计算取反；2.
 * </table>
 */ 
#include "project_board.h"
#include "bsp_uart_v2.h"
#include "wh_mb.h"
#include "bsp_adc.h"
#if USE_BSP_WDT
#include "bsp_iwdg.h"
#endif

#undef LOG_LEVEL_
#define LOG_LEVEL_ 	LOG_LVL_VERBOSE
#include "bsp_log.h"

#if DRV_BL6552_EN
#include "bl6552.h"
Bl6552_t bl6552_obj;
#endif
Gpio_t led_red_obj;
Gpio_t led_green_obj;
Gpio_t rs485_dir_obj;
Gpio_t ex_di1_obj;
Gpio_t bus_set1_obj;
Gpio_t bus_set2_obj;
Gpio_t bus_set3_obj;
Gpio_t bus_set4_obj;
Gpio_t bus_set5_obj;

Adc_t ex_ai1_obj;

MB_t mb_obj;    ///< modbus协议处理对象

static Bl6552_Energy_t g_Energy;


/**
 * @brief 温控电源板MB寄存器操作处理
 * @param[in]  reg_addr     寄存器地址
 * @param[in/out]  data     读取/写入数据
 * @param[in]  rw_flag      读写标志，0：Read，非0：Write
 * @param[in]  user_data    用户数据
 * @return uint8_t 执行结果
 * - @b Sucess : 0 \n
 * - @b Fail ：异常码（01~06）
 */
static uint8_t acp_mb_regHandle( uint16_t reg_addr, uint8_t *data, uint8_t rw_flag, void *user_data )
{
    Bl6552_Elect_t *Elect = (Bl6552_Elect_t *)user_data;

    /* 寄存器读写功能判断 */
    if ((reg_addr < 0x0119) && (rw_flag))
        return 1;   /* 不支持写 */

    switch (reg_addr)
    {
    case 0x0101:    /* 光耦DI */
    {
        data[0] = 0;
        data[1] = GpioRead( &ex_di1_obj );
    } break;

    case 0x0102:    /* 线电压频率 */
    {
        data[0] = Elect->PERIOD.byte[1];
        data[1] = Elect->PERIOD.byte[0];
    } break;

    case 0x0103:    /* A相电流有效值 */
    {
        Elect->IA_RMS.value = Elect->IA_RMS.value / 100;
        data[0] = Elect->IA_RMS.byte[1];
        data[1] = Elect->IA_RMS.byte[0];
    } break;

    case 0x0104:    /* B相电流有效值 */
    {
        Elect->IB_RMS.value = Elect->IB_RMS.value / 100;
        data[0] = Elect->IB_RMS.byte[1];
        data[1] = Elect->IB_RMS.byte[0];
    } break;

    case 0x0105:    /* C相电流有效值 */
    {
        Elect->IC_RMS.value = Elect->IC_RMS.value / 100;
        data[0] = Elect->IC_RMS.byte[1];
        data[1] = Elect->IC_RMS.byte[0];
    } break;

    case 0x0106:    /* 零线电流有效值 */
    {
        Elect->IN_RMS.value = Elect->IN_RMS.value / 100;
        data[0] = Elect->IN_RMS.byte[1];
        data[1] = Elect->IN_RMS.byte[0];
    } break;

    case 0x0107:    /* A相电压有效值 */
    {
        data[0] = Elect->VA_RMS.byte[1];
        data[1] = Elect->VA_RMS.byte[0];
    } break;

    case 0x0108:    /* B相电压有效值 */
    {
        data[0] = Elect->VB_RMS.byte[1];
        data[1] = Elect->VB_RMS.byte[0];
    } break;

    case 0x0109:    /* C相电压有效值 */
    {
        data[0] = Elect->VC_RMS.byte[1];
        data[1] = Elect->VC_RMS.byte[0];
    } break;

    case 0x010A:    /* A相有功功率 */
    {
        data[0] = Elect->WATT_A.byte[1];
        data[1] = Elect->WATT_A.byte[0];
    } break;

    case 0x010B:    /* B相有功功率 */
    {
        data[0] = Elect->WATT_B.byte[1];
        data[1] = Elect->WATT_B.byte[0];
    } break;

    case 0x010C:    /* C相有功功率 */
    {
        data[0] = Elect->WATT_C.byte[1];
        data[1] = Elect->WATT_C.byte[0];
    } break;

    case 0x010D:    /* 合相有功功率 */
    {
        data[0] = Elect->WATT.byte[1];
        data[1] = Elect->WATT.byte[0];
    } break;

    case 0x010E:    /* A相无功功率 */
    {
        data[0] = Elect->VAR_A.byte[1];
        data[1] = Elect->VAR_A.byte[0];
    } break;

    case 0x010F:    /* B相无功功率 */
    {
        data[0] = Elect->VAR_B.byte[1];
        data[1] = Elect->VAR_B.byte[0];
    } break;

    case 0x0110:    /* C相无功功率 */
    {
        data[0] = Elect->VAR_C.byte[1];
        data[1] = Elect->VAR_C.byte[0];
    } break;

    case 0x0111:    /* 合相无功功率 */
    {
        data[0] = Elect->VAR.byte[1];
        data[1] = Elect->VAR.byte[0];
    } break;

    case 0x0112:    /* 电压A相与电B相的波形夹角 */
    {
        data[0] = Elect->ANGLE_AB.byte[1];
        data[1] = Elect->ANGLE_AB.byte[0];
    } break;

    case 0x0113:    /* 电压B相与电C相的波形夹角 */
    {
        data[0] = Elect->ANGLE_BC.byte[1];
        data[1] = Elect->ANGLE_BC.byte[0];
    } break;

    case 0x0114:    /* 电压C相与电A相的波形夹角 */
    {
        data[0] = Elect->ANGLE_AC.byte[1];
        data[1] = Elect->ANGLE_AC.byte[0];
    } break;

    case 0x0115:    /* A相功率因子 */
    {
        data[0] = Elect->PF_A.byte[1];
        data[1] = Elect->PF_A.byte[0];
    } break;

    case 0x0116:    /* B相功率因子 */
    {
        data[0] = Elect->PF_B.byte[1];
        data[1] = Elect->PF_B.byte[0];
    } break;

    case 0x0117:    /* C相功率因子 */
    {
        data[0] = Elect->PF_C.byte[1];
        data[1] = Elect->PF_C.byte[0];
    } break;

    case 0x0118:    /* 合相功率因子 */
    {
        data[0] = Elect->PF.byte[1];
        data[1] = Elect->PF.byte[0];
    } break;

    case 0x0119:    /* A相有功能量(高) */
    {
        if (rw_flag)
        {
            g_Energy.Energy_A.byte[3] = data[0];
            g_Energy.Energy_A.byte[2] = data[1];
        }
        else
        {
            data[0] = g_Energy.Energy_A.byte[3];
            data[1] = g_Energy.Energy_A.byte[2];
        }
    } break;

    case 0x011A:    /* A相有功能量(低) */
    {
        if (rw_flag)
        {
            g_Energy.Energy_A.byte[1] = data[0];
            g_Energy.Energy_A.byte[0] = data[1];
        }
        else
        {
            data[0] = g_Energy.Energy_A.byte[1];
            data[1] = g_Energy.Energy_A.byte[0];
        }
    } break;

    case 0x011B:    /* B相有功能量(高) */
    {
        if (rw_flag)
        {
            g_Energy.Energy_B.byte[3] = data[0];
            g_Energy.Energy_B.byte[2] = data[1];
        }
        else
        {
            data[0] = g_Energy.Energy_B.byte[3];
            data[1] = g_Energy.Energy_B.byte[2];
        }
    } break;

    case 0x011C:    /* B相有功能量(低) */
    {
        if (rw_flag)
        {
            g_Energy.Energy_B.byte[1] = data[0];
            g_Energy.Energy_B.byte[0] = data[1];
        }
        else
        {
            data[0] = g_Energy.Energy_B.byte[1];
            data[1] = g_Energy.Energy_B.byte[0];
        }
    } break;

    case 0x011D:    /* C相有功能量(高) */
    {
        if (rw_flag)
        {
            g_Energy.Energy_C.byte[3] = data[0];
            g_Energy.Energy_C.byte[2] = data[1];
        }
        else
        {
            data[0] = g_Energy.Energy_C.byte[3];
            data[1] = g_Energy.Energy_C.byte[2];
        }
    } break;

    case 0x011E:    /* C相有功能量(低) */
    {
        if (rw_flag)
        {
            g_Energy.Energy_C.byte[1] = data[0];
            g_Energy.Energy_C.byte[0] = data[1];
        }
        else
        {
            data[0] = g_Energy.Energy_C.byte[1];
            data[1] = g_Energy.Energy_C.byte[0];
        }
    } break;

    case 0x011F:    /* 合相有功能量(高) */
    {
        if (rw_flag)
        {
            g_Energy.Energy.byte[3] = data[0];
            g_Energy.Energy.byte[2] = data[1];
        }
        else
        {
            data[0] = g_Energy.Energy.byte[3];
            data[1] = g_Energy.Energy.byte[2];
        }
    } break;

    case 0x0120:    /* 合相有功能量(低) */
    {
        if (rw_flag)
        {
            g_Energy.Energy.byte[1] = data[0];
            g_Energy.Energy.byte[0] = data[1];
            Bl6552_SetEnergy( &bl6552_obj, &g_Energy );
        }
        else
        {
            data[0] = g_Energy.Energy.byte[1];
            data[1] = g_Energy.Energy.byte[0];
        }
    } break;

    case 0x0121:    /* 加湿器电流（mA） */
    {
        if (rw_flag)
        {
            return 1;
        }
        else
        {
            uint16_t reg_value = (uint16_t)(AdcReadChannelVol(&ex_ai1_obj) * 100 / 3.3f);
            data[0] = (uint8_t)(reg_value>>8);
            data[1] = (uint8_t)(reg_value&0xFF);
        }
    } break;

    default:
        return 2;
    }

    return 0;
}


/**
 * @brief 温控电源监控板RS485协议处理
 * @param[in]  pmb          modbus协议处理对象
 * @param[in/out]  data     读取/写入数据
 * @return uint8_t 执行结果
 * - @b Sucess : 0 \n
 * - @b Fail ：异常码（01~06）
 */
static uint8_t acp_mb_handle( MB_t *pmb, uint8_t *data )
{
    uint8_t i, ret;
    log_d("mb cmd(%02X) reg_start(%04X) reg_len(%d)\r\n", pmb->pfrm.cmd, pmb->pfrm.addr_start, pmb->pfrm.addr_len);

    if (pmb->pfrm.addr == 0xFF)     /* 广播帧处理 */
    {
        if (pmb->pfrm.addr_start == 0x0401)
            NVIC_SystemReset();
        else
            return 2;   /* 非法数据地址 */
    }

    if (pmb->pfrm.cmd == 0x03)      /* 读保持寄存器 */
    {
        if (data == NULL)
            return 4;   /* 从设备故障（不会走到这个地方） */

        Bl6552_Elect_t Elect;
        if (pmb->pfrm.addr_start < 0x0118)
        {
            if (BSP_SUCCESS != Bl6552_GetElect( &bl6552_obj, &Elect, BL6552_ELECT_ALL ))
            {
                return 4;   /* 从站设备故障 */
            }
        }
        if ((pmb->pfrm.addr_start > 0x0117) || (pmb->pfrm.addr_start + pmb->pfrm.addr_len > 0x0117))
        {
            if (BSP_SUCCESS != Bl6552_GetEnergy( &bl6552_obj, &g_Energy ))
                return 4;   /* 从站设备故障 */
        }

        /* 协议回复 */
        for (i = 0; i < pmb->pfrm.addr_len; i++)
        {
            ret = acp_mb_regHandle( pmb->pfrm.addr_start + i, &data[i*2], 0, &Elect );
            if (ret != 0)
                return ret;
        }
    }
    else if (pmb->pfrm.cmd == 0x06)
    {
        ret = acp_mb_regHandle( pmb->pfrm.addr_start, data, 1, NULL );
        if (ret != 0)
            return ret;
    }
    else if (pmb->pfrm.cmd == 0x10)
    {
        for (i = 0; i < pmb->pfrm.addr_len; i++)
        {
            ret = acp_mb_regHandle( pmb->pfrm.addr_start + i, &data[i*2], 1, NULL );
            if (ret != 0)
                return ret;
        }
    }
    else
    {
        return 1;   /* 非法功能 */
    }

    return 0;
}


static void rs485_send( uint8_t *buffer, uint16_t size )
{
    GpioWrite( &rs485_dir_obj, 1 );
    UartSend( UART_1, buffer, size );
    GpioWrite( &rs485_dir_obj, 0 );
}

/**
 * @brief RS485接收任务
 */
void mb_recv_task(void *para)
{
    log_i("mb_recv_task start... \r\n");

    while(1)
    {
        uint8_t buffer[32];
        memset(buffer, 0, 32);
        int32_t recv_len = UartRecv( UART_1, buffer, 32, portMAX_DELAY );
        if( recv_len > 0)
        {
            if (recv_len > 32)
                recv_len = 32;

            log_hexdump( buffer, recv_len );
            mb_obj.frm_handle( &mb_obj, buffer, recv_len );
        }
        else
        {
            log_d("uart recv timeout\r\n");
        }

        vTaskDelay(1);
    }
}

/**
 * @brief 应用启动
 */
void acp_task(void *para)
{
    /* IO初始化 */
    GpioInit( &led_red_obj, LED_RED_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
    GpioInit( &led_green_obj, LED_GREEN_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
    GpioInit( &ex_di1_obj, EX_DI1_PIN, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );

    /* 拨码开关初始化 */
    GpioInit( &bus_set1_obj, BUS_SET1_PIN, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
    GpioInit( &bus_set2_obj, BUS_SET2_PIN, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
    GpioInit( &bus_set3_obj, BUS_SET3_PIN, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
    GpioInit( &bus_set4_obj, BUS_SET4_PIN, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
    GpioInit( &bus_set5_obj, BUS_SET5_PIN, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );

    AdcInitChannel( &ex_ai1_obj, EX_AI1_PIN );

    /* BL6552初始化 */
#if DRV_BL6552_EN
    if( BSP_SUCCESS != Bl6552_Init( &bl6552_obj, UART_2, UART2_TX_PIN, UART2_RX_PIN ) )
        log_e("Bl6552_Init fail !\r\n");
#endif


    /* MODBUS 初始化 */
    uint8_t rs485_addr = (uint8_t)(~(GpioRead(&bus_set1_obj) | (GpioRead(&bus_set2_obj)<<1) | (GpioRead(&bus_set3_obj)<<2) | (GpioRead(&bus_set4_obj)<<3) | (GpioRead(&bus_set5_obj)<<4)) & 0x1F);
    if (rs485_addr == 0) rs485_addr = 1;
    log_i("rs485_addr = %d\r\n", rs485_addr);

    mb_init( &mb_obj, rs485_addr, rs485_send, acp_mb_handle );

    /* RS485初始化 */
    GpioInit( &rs485_dir_obj, RS485_DIR_PIN, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
    if( BSP_SUCCESS != UartInit( UART_1, UART1_TX_PIN, UART1_RX_PIN, 16 ))
        log_e("Uart1 Init fail !\r\n");
    else
    {
        UartConfig( UART_1, RX_TX, 19200, UART_8_BIT, UART_1_STOP_BIT, NO_PARITY, NO_FLOW_CTRL );
        xTaskCreate( mb_recv_task, "mb_recv", 128, NULL, 14, NULL);
    }

#if USE_BSP_WDT
    iwdg_init(DEFAULT_WDT_PERIOD);
    while (1)
    {
        iwdg_feed();
        vTaskDelay(DEFAULT_WDT_PERIOD * 500);
    }
#else
    vTaskDelete( NULL );
#endif
}


void application_start(void)
{
    xTaskCreate( acp_task, "acp_task", 256, NULL, 13, NULL );
}



#if SHELL_TASK_EN
#include "nr_micro_shell.h"
/**
 * @brief 电机测试指令
 */
void acp_test_cmd(char argc, char *argv)
{
    if (argc >= 2)
    {
        if (!strcmp("led", &argv[argv[1]])) /* 红灯控制 acp led 1 */
        {
            if(argc < 3)
            {
                shell_printf("acp led need more arguments!\r\n");
                return;
            }
            GpioWrite( &led_red_obj, ((uint8_t)atoi(&argv[argv[2]]) > 0 ? 0 : 1) );
            GpioWrite( &led_green_obj, ((uint8_t)atoi(&argv[argv[2]]) > 0 ? 1 : 0) );
        }

        else if (!strcmp("getdi", &argv[argv[1]]))   /* DI测试 acp getdi */
        {
            shell_printf("ex_di1 = %d\r\n", GpioRead( &ex_di1_obj ) );
        }

#if (LOG_UART != 1)
        else if (!strcmp("rs485", &argv[argv[1]]))  /* 485发送测试 acp rs485 hello */
        {
            if(argc < 3)
            {
                shell_printf("acp led need more arguments!\r\n");
                return;
            }
            UartPrintf( UART_1, "%s\r\n", &argv[argv[2]] );
        }
#endif

#if DRV_BL6552_EN
        else if (!strcmp("bl6552", &argv[argv[1]]))
        {
            Bl6552_Elect_t Elect;
            if (BSP_SUCCESS == Bl6552_GetElect( &bl6552_obj, &Elect, BL6552_ELECT_ALL ))
            {
                shell_printf("\r\nPERIOD = %d\r\n", Elect.PERIOD.value );
                #if BL6552_USE_TPS
                shell_printf("\r\nTPS = %d\r\n", Elect.TPS1.value );
                #endif

                shell_printf("IA_RMS = %d\r\n", Elect.IA_RMS.value );
                shell_printf("IB_RMS = %d\r\n", Elect.IB_RMS.value );
                shell_printf("IC_RMS = %d\r\n", Elect.IC_RMS.value );
                shell_printf("IN_RMS = %d\r\n", Elect.IN_RMS.value );
                shell_printf("VA_RMS = %d\r\n", Elect.VA_RMS.value );
                shell_printf("VB_RMS = %d\r\n", Elect.VB_RMS.value );
                shell_printf("VC_RMS = %d\r\n", Elect.VC_RMS.value );

                shell_printf("WATT_A = %d\r\n", Elect.WATT_A.value );
                shell_printf("WATT_B = %d\r\n", Elect.WATT_B.value );
                shell_printf("WATT_C = %d\r\n", Elect.WATT_C.value );
                shell_printf("WATT = %d\r\n", Elect.WATT.value );
                #if BL6552_USE_VAR
                shell_printf("VAR_A = %d\r\n", Elect.VAR_A.value );
                shell_printf("VAR_B = %d\r\n", Elect.VAR_B.value );
                shell_printf("VAR_C = %d\r\n", Elect.VAR_C.value );
                shell_printf("VAR = %d\r\n", Elect.VAR.value );
                #endif
                #if BL6552_USE_ANGLE
                shell_printf("ANGLE_AB = %d\r\n", Elect.ANGLE_AB.value );
                shell_printf("ANGLE_BC = %d\r\n", Elect.ANGLE_BC.value );
                shell_printf("ANGLE_AC = %d\r\n", Elect.ANGLE_AC.value );
                #endif
                #if BL6552_USE_PF
                shell_printf("PF_A = %d\r\n", Elect.PF_A.value );
                shell_printf("PF_B = %d\r\n", Elect.PF_B.value );
                shell_printf("PF_C = %d\r\n", Elect.PF_C.value );
                shell_printf("PF = %d\r\n", Elect.PF.value );
                #endif
            }
        }

        else if (!strcmp("energy", &argv[argv[1]]))
        {
            if(argc < 3)
            {
                shell_printf("acp energy need more arguments!\r\n");
                return;
            }

            Bl6552_Energy_t Energy;
            memset(&Energy, 0, sizeof(Bl6552_Energy_t));
            if (!strcmp("get", &argv[argv[2]]))
            {
                Bl6552_GetEnergy( &bl6552_obj, &Energy );
#if (BL6552_ENERGY_USE_FLOAT)
                shell_printf("Energy_A = %f\r\n", Energy.Energy_A.value );
                shell_printf("Energy_B = %f\r\n", Energy.Energy_B.value );
                shell_printf("Energy_C = %f\r\n", Energy.Energy_C.value );
                shell_printf("Energy = %f\r\n", Energy.Energy.value );
#else
                shell_printf("Energy_A = %d\r\n", Energy.Energy_A.value );
                shell_printf("Energy_B = %d\r\n", Energy.Energy_B.value );
                shell_printf("Energy_C = %d\r\n", Energy.Energy_C.value );
                shell_printf("Energy = %d\r\n", Energy.Energy.value );
#endif
            }
            else if (!strcmp("clear", &argv[argv[2]]))
            {
                Bl6552_SetEnergy( &bl6552_obj, &Energy );
                shell_printf("Bl6552_SetEnergy ok\r\n");
            }
            else if (!strcmp("set", &argv[argv[2]]))    /* acp energy set 0 0 0 0 */
            {
                if(argc < 7)
                {
                    shell_printf("acp energy need more arguments!\r\n");
                    return;
                }
                Energy.Energy_A.value = atoi(&argv[argv[3]]);
                Energy.Energy_B.value = atoi(&argv[argv[4]]);
                Energy.Energy_C.value = atoi(&argv[argv[5]]);
                Energy.Energy.value = atoi(&argv[argv[6]]);
                Bl6552_SetEnergy( &bl6552_obj, &Energy );
                shell_printf("Bl6552_SetEnergy ok\r\n");
            }
        }
#endif
    }
    else
    {
        shell_printf("acp need more arguments!\r\n");
    }
}
NR_SHELL_CMD_EXPORT(acp, acp_test_cmd);
#endif  /* SHELL_TASK_EN */


/*********** (C) COPYRIGHT 2021 FiberHome *****END OF FILE****/
